package com.soap.desensitize.strategy.rreversible.asymmetric;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import com.soap.desensitize.encry.rreversible.asymmetric.AbstractAsymmetryEncry;
import com.soap.desensitize.exception.strategy.DecodeException;
import com.soap.desensitize.exception.strategy.EncodeException;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;


public class RsaStrategy extends AbstractAsymmetryEncry<String> {
    private static String algorithm = "RSA";
    private static RsaStrategy instance = null;
    private RsaStrategy(){}

    /**
     * @desc 获得实例
     * @return
     */
    public static synchronized RsaStrategy getInstance(){
        if(instance == null){
            instance = new RsaStrategy();
        }
        return instance;
    }

    /**
     * @desc 公钥字符串转key
     * @param publicKeyString
     * @return
     * @throws Exception
     */
    public PublicKey publicKeyStringToKey(String publicKeyString) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] publicBytes = Base64.getDecoder().decode(publicKeyString);
        PublicKey publicKey = null;
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicBytes));
        return publicKey;
    }

    /**
     * 公钥加密
     *
     * @param input     明文
     * @param publicKey 公钥
     * @return 密文字符串
     * @throws Exception
     */
    public String pkEncoded(String input, String publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
        byte[] cipherText = new byte[0];

        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.ENCRYPT_MODE, publicKeyStringToKey(publicKey));
        cipherText = cipher.doFinal(bytes);

        return Base64.getEncoder().encodeToString(cipherText);
    }

    public PrivateKey privateKeyStringToKey(String privateKeyString){
        byte[] privateBytes = Base64.getDecoder().decode(privateKeyString);
        PrivateKey privateKey = null;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateBytes));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
        return privateKey;
    }

    /**
     * 私钥解密
     *
     * @param cipherText 密文
     * @param privateKey 私钥
     * @return 明文字符串
     * @throws Exception
     */
    public String skDecoded(String cipherText, String privateKey) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        byte[] cipherbytes = Base64.getDecoder().decode(cipherText);
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE, privateKeyStringToKey(privateKey));
        byte[] input = cipher.doFinal(cipherbytes);
        return new String(input);

    }



	@Override
	public String encode(String data) throws EncodeException {
        String pkStr = null;
        try {
            pkStr = pkEncoded(data, pk);
        } catch (NoSuchPaddingException e) {
            throw new EncodeException("无此类删除异常 "+e.getMessage());
        } catch (InvalidKeySpecException e) {
            throw new EncodeException("无效键说明异常 "+e.getMessage());
        } catch (IllegalBlockSizeException e) {
            throw new EncodeException("非法块大小异常 "+e.getMessage());
        } catch (BadPaddingException e) {
            throw new EncodeException("填充异常 "+e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            throw new EncodeException("未找到该算法 "+e.getMessage());
        } catch (InvalidKeyException e) {
            throw new EncodeException(e.getMessage());
        }
        return pkStr;
	}

	@Override
	public String decode(String data) throws DecodeException {
        String pkStr = null;
        try {
            pkStr = skDecoded(data, sk);
        } catch (NoSuchPaddingException e) {
            throw new RuntimeException(e);
        } catch (IllegalBlockSizeException e) {
            throw new DecodeException("非法块大小异常 "+e.getMessage());
        } catch (BadPaddingException e) {
            throw new DecodeException("填充异常 "+e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            throw new DecodeException("未找到该算法 "+e.getMessage());
        } catch (InvalidKeyException e) {
            throw new DecodeException(e.getMessage());
        }
        return pkStr;

	}

}
